package com.clear.honghefinance.biz.modules.system.role.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.clear.honghefinance.biz.modules.system.role.domain.entity.SysRoleBindMenu;
import com.clear.honghefinance.biz.modules.system.member.domain.vo.AdminDTO;
import com.clear.honghefinance.biz.modules.system.role.domain.dto.RoleBindMenuDTO;
import com.clear.honghefinance.biz.modules.system.role.mapper.SysRoleBindMenuMapper;
import com.clear.honghefinance.biz.modules.system.role.service.ISysRoleBindMenuService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.clear.honghefinance.common.exception.BizException;
import com.clear.honghefinance.common.service.TokenService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.support.TransactionTemplate;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;

/**
 * <p>
 * 系统角色绑定菜单 服务实现类
 * </p>
 *
 * @author 程序员clear
 * @since 2024-08-15
 */
@Service
@Slf4j
public class SysRoleBindMenuServiceImpl extends ServiceImpl<SysRoleBindMenuMapper, SysRoleBindMenu> implements ISysRoleBindMenuService {

    @Resource
    private TokenService<AdminDTO> tokenService;
    @Resource
    private TransactionTemplate transactionTemplate;

    /**
     * 角色绑定菜单
     *
     * @param dto
     * @return
     */
    @Override
    public boolean roleBindMenu(RoleBindMenuDTO dto) {
        // 只要传入的bindMenuIds、unBindMenuIds都会为空，就认为无需更改。具体的复选框状态由前端处理
        if (CollectionUtils.isEmpty(dto.getBindMenuIds()) && CollectionUtils.isEmpty(dto.getUnBindMenuIds())) {
            throw new BizException("您未做任何更改，不能提交绑定");
        }
        List<SysRoleBindMenu> sysRoleBindMenuList = new ArrayList<>();
        if (CollectionUtils.isNotEmpty(dto.getBindMenuIds())) {
            // 1.检测角色是否已经绑定过菜单
            checkRoleBindMenuIds(dto.getRoleId(), dto.getBindMenuIds());
            // 2.遍历菜单id列表，封装成实体类
            for (Integer menuId : dto.getBindMenuIds()) {
                SysRoleBindMenu sysRoleBindMenu = new SysRoleBindMenu();
                sysRoleBindMenu.setSysRoleId(dto.getRoleId());
                sysRoleBindMenu.setSysMenuId(menuId);
                sysRoleBindMenu.setMemberId(tokenService.getThreadLocalUserId());
                sysRoleBindMenu.setUpdateMemberId(tokenService.getThreadLocalUserId());
                sysRoleBindMenu.initDefault();

                sysRoleBindMenuList.add(sysRoleBindMenu);
            }
        }
        // 3.编程式事务，批量插入
        transactionTemplate.execute((transactionStatus) -> {
            // 角色绑定菜单
            if (CollectionUtils.isNotEmpty(dto.getBindMenuIds())) {
                return this.saveBatch(sysRoleBindMenuList);
            }
            // 角色取消绑定菜单
            if (CollectionUtils.isNotEmpty(dto.getUnBindMenuIds())) {
                LambdaUpdateWrapper<SysRoleBindMenu> lambdaUpdateWrapper = Wrappers.<SysRoleBindMenu>lambdaUpdate()
                        .eq(SysRoleBindMenu::getSysRoleId, dto.getRoleId())
                        .eq(SysRoleBindMenu::getDelFlag, false)
                        .in(SysRoleBindMenu::getSysMenuId, dto.getUnBindMenuIds())
                        // 逻辑删除：即角色绑定菜单
                        .set(SysRoleBindMenu::getDelFlag, true);

                boolean updateRows = this.update(null, lambdaUpdateWrapper);
                if (!updateRows) {
                    throw new BizException("解绑失败");
                }
            }
            return true;
        });
        return true;
    }

    /**
     * 查看角色绑定的菜单id列表
     *
     * @param roleId 角色id
     * @return 菜单id列表
     */
    @Override
    public List<Integer> listBindMenuIdByRoleId(int roleId) {
        LambdaQueryWrapper<SysRoleBindMenu> lambdaQueryWrapper = Wrappers.<SysRoleBindMenu>lambdaQuery()
                .select(SysRoleBindMenu::getSysMenuId)
                .eq(SysRoleBindMenu::getSysRoleId, roleId)
                .eq(SysRoleBindMenu::getDelFlag, false);
        List<SysRoleBindMenu> roleBindMenuList = this.list(lambdaQueryWrapper);

        if (CollectionUtils.isNotEmpty(roleBindMenuList)) {
            return roleBindMenuList.stream().map(SysRoleBindMenu::getSysMenuId).collect(Collectors.toList());
        }
        return Collections.emptyList();
    }

    /**
     * 检测角色是否已经绑定过菜单
     *
     * @param roleId  角色id
     * @param menuIds 菜单id列表
     */

    private void checkRoleBindMenuIds(int roleId, List<Integer> menuIds) {
        LambdaQueryWrapper<SysRoleBindMenu> lambdaQueryWrapper = Wrappers.<SysRoleBindMenu>lambdaQuery()
                .eq(SysRoleBindMenu::getSysRoleId, roleId)
                .in(SysRoleBindMenu::getSysMenuId, menuIds)
                .eq(SysRoleBindMenu::getDelFlag, false);
        int count = this.count(lambdaQueryWrapper);
        if (count > 0) {
            throw new BizException("角色不要重复绑定菜单");
        }
    }
}
